home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / pyshared / PIL / EpsImagePlugin.py < prev    next >
Text File  |  2006-12-03  |  10KB  |  350 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: EpsImagePlugin.py 2134 2004-10-06 08:55:20Z fredrik $
  4. #
  5. # EPS file handling
  6. #
  7. # History:
  8. # 1995-09-01 fl   Created (0.1)
  9. # 1996-05-18 fl   Don't choke on "atend" fields, Ghostscript interface (0.2)
  10. # 1996-08-22 fl   Don't choke on floating point BoundingBox values
  11. # 1996-08-23 fl   Handle files from Macintosh (0.3)
  12. # 2001-02-17 fl   Use 're' instead of 'regex' (Python 2.1) (0.4)
  13. # 2003-09-07 fl   Check gs.close status (from Federico Di Gregorio) (0.5)
  14. #
  15. # Copyright (c) 1997-2003 by Secret Labs AB.
  16. # Copyright (c) 1995-2003 by Fredrik Lundh
  17. #
  18. # See the README file for information on usage and redistribution.
  19. #
  20.  
  21. __version__ = "0.5"
  22.  
  23. import re, string
  24. import Image, ImageFile
  25.  
  26. #
  27. # --------------------------------------------------------------------
  28.  
  29. def i32(c):
  30.     return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
  31.  
  32. def o32(i):
  33.     return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
  34.  
  35. split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$")
  36. field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$")
  37.  
  38. def Ghostscript(tile, size, fp):
  39.     """Render an image using Ghostscript (Unix only)"""
  40.  
  41.     # Unpack decoder tile
  42.     decoder, tile, offset, data = tile[0]
  43.     length, bbox = data
  44.  
  45.     import tempfile, os
  46.  
  47.     file = tempfile.mktemp()
  48.  
  49.     # Build ghostscript command
  50.     command = ["gs",
  51.                "-q",                    # quite mode
  52.                "-g%dx%d" % size,        # set output geometry (pixels)
  53.                "-dNOPAUSE -dSAFER",     # don't pause between pages, safe mode
  54.                "-sDEVICE=ppmraw",       # ppm driver
  55.                "-sOutputFile=%s" % file,# output file
  56.                "- >/dev/null 2>/dev/null"]
  57.  
  58.     command = string.join(command)
  59.  
  60.     # push data through ghostscript
  61.     try:
  62.         gs = os.popen(command, "w")
  63.         # adjust for image origin
  64.         if bbox[0] != 0 or bbox[1] != 0:
  65.             gs.write("%d %d translate\n" % (-bbox[0], -bbox[1]))
  66.         fp.seek(offset)
  67.         while length > 0:
  68.             s = fp.read(8192)
  69.             if not s:
  70.                 break
  71.             length = length - len(s)
  72.             gs.write(s)
  73.         status = gs.close()
  74.         if status:
  75.             raise IOError("gs failed (status %d)" % status)
  76.         im = Image.core.open_ppm(file)
  77.     finally:
  78.         try: os.unlink(file)
  79.         except: pass
  80.  
  81.     return im
  82.  
  83.  
  84. class PSFile:
  85.     """Wrapper that treats either CR or LF as end of line."""
  86.     def __init__(self, fp):
  87.         self.fp = fp
  88.         self.char = None
  89.     def __getattr__(self, id):
  90.         v = getattr(self.fp, id)
  91.         setattr(self, id, v)
  92.         return v
  93.     def seek(self, offset, whence=0):
  94.         self.char = None
  95.         self.fp.seek(offset, whence)
  96.     def tell(self):
  97.         pos = self.fp.tell()
  98.         if self.char:
  99.             pos = pos - 1
  100.         return pos
  101.     def readline(self):
  102.         s = ""
  103.         if self.char:
  104.             c = self.char
  105.             self.char = None
  106.         else:
  107.             c = self.fp.read(1)
  108.         while c not in "\r\n":
  109.             s = s + c
  110.             c = self.fp.read(1)
  111.         if c == "\r":
  112.             self.char = self.fp.read(1)
  113.             if self.char == "\n":
  114.                 self.char = None
  115.         return s + "\n"
  116.  
  117.  
  118. def _accept(prefix):
  119.     return prefix[:4] == "%!PS" or i32(prefix) == 0xC6D3D0C5L
  120.  
  121. ##
  122. # Image plugin for Encapsulated Postscript.  This plugin supports only
  123. # a few variants of this format.
  124.  
  125. class EpsImageFile(ImageFile.ImageFile):
  126.     """EPS File Parser for the Python Imaging Library"""
  127.  
  128.     format = "EPS"
  129.     format_description = "Encapsulated Postscript"
  130.  
  131.     def _open(self):
  132.  
  133.         # FIXME: should check the first 512 bytes to see if this
  134.         # really is necessary (platform-dependent, though...)
  135.  
  136.         fp = PSFile(self.fp)
  137.  
  138.         # HEAD
  139.         s = fp.read(512)
  140.         if s[:4] == "%!PS":
  141.             offset = 0
  142.             fp.seek(0, 2)
  143.             length = fp.tell()
  144.         elif i32(s) == 0xC6D3D0C5L:
  145.             offset = i32(s[4:])
  146.             length = i32(s[8:])
  147.             fp.seek(offset)
  148.         else:
  149.             raise SyntaxError, "not an EPS file"
  150.  
  151.         fp.seek(offset)
  152.  
  153.         box = None
  154.  
  155.         self.mode = "RGB"
  156.         self.size = 1, 1 # FIXME: huh?
  157.  
  158.         #
  159.         # Load EPS header
  160.  
  161.         s = fp.readline()
  162.  
  163.         while s:
  164.  
  165.             if len(s) > 255:
  166.                 raise SyntaxError, "not an EPS file"
  167.  
  168.             if s[-2:] == '\r\n':
  169.                 s = s[:-2]
  170.             elif s[-1:] == '\n':
  171.                 s = s[:-1]
  172.  
  173.             try:
  174.                 m = split.match(s)
  175.             except re.error, v:
  176.                 raise SyntaxError, "not an EPS file"
  177.  
  178.             if m:
  179.                 k, v = m.group(1, 2)
  180.                 self.info[k] = v
  181.                 if k == "BoundingBox":
  182.                     try:
  183.                         # Note: The DSC spec says that BoundingBox
  184.                         # fields should be integers, but some drivers
  185.                         # put floating point values there anyway.
  186.                         box = map(int, map(float, string.split(v)))
  187.                         self.size = box[2] - box[0], box[3] - box[1]
  188.                         self.tile = [("eps", (0,0) + self.size, offset,
  189.                                       (length, box))]
  190.                     except:
  191.                         pass
  192.  
  193.             else:
  194.  
  195.                 m = field.match(s)
  196.  
  197.                 if m:
  198.                     k = m.group(1)
  199.                     if k == "EndComments":
  200.                         break
  201.                     if k[:8] == "PS-Adobe":
  202.                         self.info[k[:8]] = k[9:]
  203.                     else:
  204.                         self.info[k] = ""
  205.                 else:
  206.                     raise IOError, "bad EPS header"
  207.  
  208.             s = fp.readline()
  209.  
  210.             if s[:1] != "%":
  211.                 break
  212.  
  213.  
  214.         #
  215.         # Scan for an "ImageData" descriptor
  216.  
  217.         while s[0] == "%":
  218.  
  219.             if len(s) > 255:
  220.                 raise SyntaxError, "not an EPS file"
  221.  
  222.             if s[-2:] == '\r\n':
  223.                 s = s[:-2]
  224.             elif s[-1:] == '\n':
  225.                 s = s[:-1]
  226.  
  227.             if s[:11] == "%ImageData:":
  228.  
  229.                 [x, y, bi, mo, z3, z4, en, id] =\
  230.                     string.split(s[11:], maxsplit=7)
  231.  
  232.                 x = int(x); y = int(y)
  233.  
  234.                 bi = int(bi)
  235.                 mo = int(mo)
  236.  
  237.                 en = int(en)
  238.  
  239.                 if en == 1:
  240.                     decoder = "eps_binary"
  241.                 elif en == 2:
  242.                     decoder = "eps_hex"
  243.                 else:
  244.                     break
  245.                 if bi != 8:
  246.                     break
  247.                 if mo == 1:
  248.                     self.mode = "L"
  249.                 elif mo == 2:
  250.                     self.mode = "LAB"
  251.                 elif mo == 3:
  252.                     self.mode = "RGB"
  253.                 else:
  254.                     break
  255.  
  256.                 if id[:1] == id[-1:] == '"':
  257.                     id = id[1:-1]
  258.  
  259.                 # Scan forward to the actual image data
  260.                 while 1:
  261.                     s = fp.readline()
  262.                     if not s:
  263.                         break
  264.                     if s[:len(id)] == id:
  265.                         self.size = x, y
  266.                         self.tile2 = [(decoder,
  267.                                        (0, 0, x, y),
  268.                                        fp.tell(),
  269.                                        0)]
  270.                         return
  271.  
  272.             s = fp.readline()
  273.             if not s:
  274.                 break
  275.  
  276.         if not box:
  277.             raise IOError, "cannot determine EPS bounding box"
  278.  
  279.     def load(self):
  280.         # Load EPS via Ghostscript
  281.         if not self.tile:
  282.             return
  283.         self.im = Ghostscript(self.tile, self.size, self.fp)
  284.         self.mode = self.im.mode
  285.         self.size = self.im.size
  286.         self.tile = []
  287.  
  288. #
  289. # --------------------------------------------------------------------
  290.  
  291. def _save(im, fp, filename, eps=1):
  292.     """EPS Writer for the Python Imaging Library."""
  293.  
  294.     #
  295.     # make sure image data is available
  296.     im.load()
  297.  
  298.     #
  299.     # determine postscript image mode
  300.     if im.mode == "L":
  301.         operator = (8, 1, "image")
  302.     elif im.mode == "RGB":
  303.         operator = (8, 3, "false 3 colorimage")
  304.     elif im.mode == "CMYK":
  305.         operator = (8, 4, "false 4 colorimage")
  306.     else:
  307.         raise ValueError, "image mode is not supported"
  308.  
  309.     if eps:
  310.         #
  311.         # write EPS header
  312.         fp.write("%!PS-Adobe-3.0 EPSF-3.0\n")
  313.         fp.write("%%Creator: PIL 0.1 EpsEncode\n")
  314.         #fp.write("%%CreationDate: %s"...)
  315.         fp.write("%%%%BoundingBox: 0 0 %d %d\n" % im.size)
  316.         fp.write("%%Pages: 1\n")
  317.         fp.write("%%EndComments\n")
  318.         fp.write("%%Page: 1 1\n")
  319.         fp.write("%%ImageData: %d %d " % im.size)
  320.         fp.write("%d %d 0 1 1 \"%s\"\n" % operator)
  321.  
  322.     #
  323.     # image header
  324.     fp.write("gsave\n")
  325.     fp.write("10 dict begin\n")
  326.     fp.write("/buf %d string def\n" % (im.size[0] * operator[1]))
  327.     fp.write("%d %d scale\n" % im.size)
  328.     fp.write("%d %d 8\n" % im.size) # <= bits
  329.     fp.write("[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1]))
  330.     fp.write("{ currentfile buf readhexstring pop } bind\n")
  331.     fp.write("%s\n" % operator[2])
  332.  
  333.     ImageFile._save(im, fp, [("eps", (0,0)+im.size, 0, None)])
  334.  
  335.     fp.write("\n%%%%EndBinary\n")
  336.     fp.write("grestore end\n")
  337.     fp.flush()
  338.  
  339. #
  340. # --------------------------------------------------------------------
  341.  
  342. Image.register_open(EpsImageFile.format, EpsImageFile, _accept)
  343.  
  344. Image.register_save(EpsImageFile.format, _save)
  345.  
  346. Image.register_extension(EpsImageFile.format, ".ps")
  347. Image.register_extension(EpsImageFile.format, ".eps")
  348.  
  349. Image.register_mime(EpsImageFile.format, "application/postscript")
  350.